package hedron.ui;

import static hedron.i18n.Internationalization._;
import hedron.Activator;
import hedron.Application;
import hedron.xml.XMLDOM;
import hedron.xml.XMLParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;

public class UIFactory {

	private static final String ID_ATTRIBUTE_NAME = "id";

	// <layout columns="4">
	// <label text />
	// <button text default icon/>
	// <text text readonly />
	// <table fullselection />
	// <list multiselection />
	// <combo readonly />
	// <spinner />
	// <container columns />--sub tags
	// <section text/> --sub tags
	// <splitter horizontal /> --sub tags
	// </layout>
	public final static Map<String, Control> createUI(Composite parent, String componentXML, FormToolkit toolkit) {
		XMLDOM parser = new XMLDOM(true);
		try {
			parser.parseString(componentXML);
			if ("layout".equals(parser.getName()) && parser.countChildren() > 0) {
				Map<String, Control> components = new HashMap<String, Control>();
				defineGrid(parent, parser);
				defineLayout(parent, parser);
				createSubComponents(components, parent, parser, toolkit);
				return components;
			}
		} catch (XMLParseException e) {
			Application.log.log(Level.SEVERE, "UI xml parsing", e);
		}

		return null;
	}

	private final static void createSubComponents(Map<String, Control> components, Composite parent,
			XMLDOM parser, FormToolkit toolkit) {

		for (XMLDOM tag : parser.getChildren()) {
			final String tagName = tag.getName();
			if ("label".equals(tagName)) {
				createLabel(components, parent, tag, toolkit);
			} else if ("button".equals(tagName)) {
				createButton(components, parent, tag, toolkit);
			} else if ("text".equals(tagName)) {
				createText(components, parent, tag, toolkit);
			} else if ("table".equals(tagName)) {
				createTable(components, parent, tag, toolkit);
			} else if ("list".equals(tagName)) {
				createList(components, parent, tag);
			} else if ("combo".equals(tagName)) {
				createCombo(components, parent, tag);
			} else if ("spinner".equals(tagName)) {
				createSpinner(components, parent, tag);
			} else if ("container".equals(tagName)) {
				createContainer(components, parent, tag, toolkit);
			} else if ("section".equals(tagName)) {
				createSection(components, parent, tag, toolkit);
			} else if ("splitter".equals(tagName)) {
				createSplitter(components, parent, tag, toolkit);
			}
		}
	}

	private final static void defineGrid(Composite component, XMLDOM tag) {
		GridLayout layout = new GridLayout();
		int value = tag.getIntAttribute("columns", 1);
		layout.numColumns = value;
		layout.marginWidth = 1;
		layout.marginHeight = 1;
		component.setLayout(layout);
	}

	private final static int getAlignment(String align) {
		final int len = (align == null) ? 0 : align.length();
		if (6 == len) {// CENTER
			return GridData.CENTER;
		} else if (3 == len) {// END
			return GridData.END;
		} else if (4 == len) {// FILL
			return GridData.FILL;
		}
		return GridData.BEGINNING;
	}

	// <xxxxxx colspan="2" rowspan="2" width="100" height="20"
	// align="BEGINING|CENTER|END|FILL" valign="BEGIN|CENTER|END|FILL"/>
	private static final void defineLayout(Control control, XMLDOM tag) {

		int align = getAlignment(tag.getAttribute("align"));
		int valign = getAlignment(tag.getAttribute("valign"));
		GridData gdata = new GridData(align, valign, align == GridData.FILL, valign == GridData.FILL);
		gdata.horizontalIndent = 0;
		gdata.verticalIndent = 0;
		{
			final int value = tag.getIntAttribute("width", 0);
			if (value != 0) gdata.widthHint = value;
		}
		{
			final int value = tag.getIntAttribute("height", 0);
			if (value != 0) gdata.heightHint = value;
		}
		{
			final int value = tag.getIntAttribute("colspan", 0);
			if (value != 0) gdata.horizontalSpan = value;
		}
		{
			final int value = tag.getIntAttribute("rowspan", 0);
			if (value != 0) gdata.verticalSpan = value;
		}

		control.setLayoutData(gdata);
	}

	// <button name="javaName" text="buttonText" default="true" />
	private final static void createButton(Map<String, Control> components, Composite parent, XMLDOM tag,
			FormToolkit toolkit) {
		int style = SWT.PUSH;
		final boolean readonly = tag.getBooleanAttribute("check");
		if (readonly) style = SWT.CHECK;

		Button button = (toolkit == null) ? new Button(parent, style) : toolkit.createButton(parent, "", style);
		defineLayout(button, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, button);
			}
		}
		{
			final String value = tag.getAttribute("text");
			if (value != null) {
				button.setText(_(value));
			}
		}
		{
			final String value = tag.getAttribute("icon");
			if (value != null) {
				button.setImage(Activator.getImage(value));
			}
		}

		{
			final boolean value = tag.getBooleanAttribute("default");
			if (value) {
				Shell shell = button.getShell();
				if (shell != null) {
					shell.setDefaultButton(button);
				}
			}
		}
	}

	// <label name="javaName" text="labelText"/>
	private final static void createLabel(Map<String, Control> components, Composite parent, XMLDOM tag,
			FormToolkit toolkit) {
		Label label = (toolkit == null) ? new Label(parent, 0) : toolkit.createLabel(parent, "");
		defineLayout(label, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, label);
			}
		}
		{
			final String value = tag.getAttribute("text");
			if (value != null) {
				label.setText(_(value));
			}
		}
	}

	// <text name="javaName" text="labelText" readonly="true" html="true"
	// multi="true" wrap="true" hscroll="true" vscroll="true"/>
	private final static void createText(Map<String, Control> components, Composite parent, XMLDOM tag,
			FormToolkit toolkit) {
		final boolean readonly = tag.getBooleanAttribute("readonly");
		final boolean html = tag.getBooleanAttribute("html");
		final boolean multi = tag.getBooleanAttribute("multi");
		final boolean wrap = tag.getBooleanAttribute("wrap");
		final boolean hscroll = tag.getBooleanAttribute("hscroll");
		final boolean vscroll = tag.getBooleanAttribute("vscroll");
		int style = SWT.BORDER;
		if (readonly) style |= SWT.READ_ONLY;
		if (multi) style |= SWT.MULTI;
		if (wrap) style |= SWT.WRAP;
		if (hscroll) style |= SWT.H_SCROLL;
		if (vscroll) style |= SWT.V_SCROLL;
		
		final Control text;
		if (toolkit == null) {
			text = new Text(parent, style);
		} else {
			if (html) {
				text = toolkit.createFormText(parent, false);
			} else {
				text = toolkit.createText(parent, "", style);
			}
		}

		defineLayout(text, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, text);
			}
		}
		{
			final String value = tag.getAttribute("text");
			if (value != null && text instanceof Text) {
				((Text) text).setText(_(value));
			}
		}
	}

	// <table name="javaName" fullselection="true"/>
	private final static void createTable(Map<String, Control> components, Composite parent, XMLDOM tag,
			FormToolkit toolkit) {
		int style = 0;
		final boolean readonly = tag.getBooleanAttribute("fullselection");
		if (readonly) style |= SWT.FULL_SELECTION;

		Table table = (toolkit == null) ? new Table(parent, style) : toolkit.createTable(parent, style);
		defineLayout(table, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, table);
			}
		}
	}

	// <list name="javaName" multiselection="true"/>
	private final static void createList(Map<String, Control> components, Composite parent, XMLDOM tag) {
		int style = SWT.BORDER | SWT.V_SCROLL;
		final boolean readonly = tag.getBooleanAttribute("multiselection");
		if (readonly) style |= SWT.MULTI;

		List list = new List(parent, style);
		defineLayout(list, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, list);
			}
		}
	}

	// <combo name="javaName" readonly="true"/>
	private final static void createCombo(Map<String, Control> components, Composite parent, XMLDOM tag) {
		int style = SWT.BORDER;
		final boolean readonly = tag.getBooleanAttribute("readonly");
		if (readonly) style |= SWT.READ_ONLY;

		Combo combo = new Combo(parent, style);
		defineLayout(combo, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, combo);
			}
		}
	}

	// <spinner name="javaName" />
	private final static void createSpinner(Map<String, Control> components, Composite parent, XMLDOM tag) {
		Spinner spinner = new Spinner(parent, SWT.BORDER);
		defineLayout(spinner, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, spinner);
			}
		}
	}

	// <container />
	private final static void createContainer(Map<String, Control> components, Composite parent, XMLDOM tag,
			FormToolkit toolkit) {
		Composite grid = (toolkit == null) ? new Composite(parent, 0) : toolkit.createComposite(parent, 0);
		defineGrid(grid, tag);
		defineLayout(grid, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, grid);
			}
		}
		createSubComponents(components, grid, tag, toolkit);
	}

	// <section text />
	private final static void createSection(Map<String, Control> components, Composite parent, XMLDOM tag,
			FormToolkit toolkit) {
		Section section = (toolkit == null) ? new Section(parent, Section.TITLE_BAR) : toolkit.createSection(parent,
				Section.TITLE_BAR);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, section);
			}
		}
		{
			final String value = tag.getAttribute("text");
			if (value != null) {
				section.setText(_(value));
			}
		}
		section.marginWidth = 1;
		section.marginHeight = 1;
		defineLayout(section, tag);

		Composite grid = (toolkit == null) ? new Composite(section, 0) : toolkit.createComposite(section, SWT.WRAP);
		section.setClient(grid);
		if (toolkit != null) toolkit.paintBordersFor(grid);
		defineGrid(grid, tag);

		createSubComponents(components, grid, tag, toolkit);
	}

	// <splitter horizontal vertical/> --sub tags
	private final static void createSplitter(Map<String, Control> components, Composite parent, XMLDOM tag,
			FormToolkit toolkit) {
		final int horizontal = tag.getIntAttribute("horizontal", 0);
		final int vertical = tag.getIntAttribute("vertical", 0);

		int style;
		int size;
		if (vertical != 0) {
			style = SWT.VERTICAL;
			size = vertical;
		} else {
			style = SWT.HORIZONTAL;
			size = horizontal;
		}
		SashForm splitter = new SashForm(parent, style);
		splitter.setSashWidth(2);
		defineLayout(splitter, tag);
		{
			final String value = tag.getAttribute(ID_ATTRIBUTE_NAME);
			if (value != null) {
				components.put(value, splitter);
			}
		}

		createSubComponents(components, splitter, tag, toolkit);

		if (size > 0 && size < 100) {
			splitter.setWeights(new int[] { size, 100 - size });
		} else {
			splitter.setWeights(new int[] { 50, 50 });
		}

	}
}
